using System;
using SQLRunnerLib.Services;
using SQLServices.Runners;
using SQLServices.Runners.Events;
using SQLServices.TransMgr;

namespace SQLRunnerLib.TransMgr
{
    /// <summary>
    /// This transaction manager does not use a transaction to execute the scripts.
    /// However this manager tries to use one connection to the database as long as possible.
    /// If an exception takes place the connection is discarted and a new one 
    /// is used. It also checks that once each script is executed that there
    /// is not a transaction open in the connection, if so then it discarts the
    /// connection and a new one is created for the next script.
    /// This manager does not have the problems of the Naive mgr and performs better than
    /// the strict mgr. If you dont need a transaction to rollback the scripts this
    /// should be the default transaction manager to use.
    /// </summary>
    class PessimistConnMgr:AbstractManager
    {
        public PessimistConnMgr(IRunner runner) : base(runner)
        {

        }

        /// <summary>
        /// When the Runner has finished the execution of all scripts it calls this method.
        /// This manager closes the connection when the scripts are executed.
        /// </summary>
        protected override void OnExecutionFinished(object sender, ExecutionFinishedEventArgs e)
        {
            CleanConnection();
        }

        /// <summary>
        /// Called when an exception is returned when a script is executed.
        /// This manager closes the connection if an exception occurs.
        /// </summary>
        protected override void OnScriptError(object sender, ScriptExecutionErrorEventArgs e)
        {
            CleanConnection();
            LogMsg("Connection was closed as a result of script exception");
        }

        /// <summary>
        /// Called after a script has been executed.
        /// This manager checks that there is not a transaction started in the connection once
        /// the script was executed, if so then it closes the connection. Please note that
        /// would rollback the last script update.
        /// </summary>
        protected override void OnScriptExecuted(object sender, ScriptExecutedEventArgs e)
        {
            return;
        }

        /// <summary>
        /// Hook into the execution process that runs before the execution takes place
        /// It checks if a transaction was left open, if so it closes the transaction (which
        /// rollbacks it) and throws a ConnMgrException
        /// </summary>
        protected override void DoAfterExecution()
        {
            long trancount = _mainConn.GetTranCount();
            if (trancount == 0) return;
            CleanConnection();
            LogMsg("Transaction was left open and connection was closed");
            throw new ConnMgrException("A transaction was left open after the script was executed, " +
                "the connection has been closed rolling back any updates since the transaction was started.");
        }

        /// <summary>
        /// Hook into the execution process that runs just after the execution of the script.
        /// It checks that a connection is available just before the script is executed.
        /// </summary>
        protected override void DoBeforeExecution()
        {
            if (_mainConn != null) return;
            _mainConn = ServiceContainer.SQLConnection.GetDatabase().Clone();
            LogMsg("Connection was created");
        }
    }
}
